package it.mauriziobasile.andoid.aub.net;

import it.mauriziobasile.andoid.aub.model.Hosts;
import it.mauriziobasile.andoid.aub.utils.CacheObj;
import it.mauriziobasile.andoid.aub.utils.CacheUtil;
import it.mauriziobasile.andoid.aub.utils.Logger;
import it.mauriziobasile.andoid.aub.utils.Tools;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpStatus;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import android.content.Context;

public class HostDefinitionDownloader {

    private static HostDefinitionDownloader _instance;
    private ExecutorService mExecutor = Executors.newFixedThreadPool(3);

    public static final HostDefinitionDownloader getInstance() {
        if (_instance == null) {
            _instance = new HostDefinitionDownloader();
        }
        return _instance;
    }

    public void getHostsDefinitions(String url, AsynchProcessListener listener, Context context) {
        GetHostsDefinitionTask task = new GetHostsDefinitionTask(url, listener, context);
        mExecutor.execute(task);
    }

    private class GetHostsDefinitionTask implements Runnable {
        private AsynchProcessListener mListener;
        private String mUrl;
        private CacheObj mCached;
        private Context mContext;

        public GetHostsDefinitionTask(String url, AsynchProcessListener listener, Context context) {
            mListener = listener;
            mUrl = url;
            mContext = context;
            mCached = CacheUtil.getFromCache(context);
        }

        public void run() {
            try {
                URL urls = new URL(mUrl);
                Logger.d("fetching " + mUrl);
                HttpURLConnection connection = null;
                int retry = 3;
                boolean connectHasException = false;
                boolean connectMustRetry = false;
                int respCode = -1;
                do {
                    try {
                        connection = (HttpURLConnection) urls.openConnection();
                        if (mCached != null && mCached.getObject() != null && mCached.getTimestamp() != null) {
                            connection.addRequestProperty("If-Modified-Since", Tools.formatDateForHttpRequest(mCached.getTimestamp()));
                        }
                        Logger.d("try [" + retry + "] conn to --> " + mUrl);
                        connectHasException = false;
                        connection.connect();
                        respCode = connection.getResponseCode();
                        Logger.d("Response code [" + respCode + "]");
                        retry--;
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                    } catch (Exception e) {
                        retry--;
                        connectHasException = true;
                    }
                    connectMustRetry = retry > 0 && (connectHasException || (respCode != HttpStatus.SC_OK && respCode != HttpStatus.SC_NOT_MODIFIED));
                } while (connectMustRetry);
                InputStream inputStream = connection.getInputStream();

                if (respCode == HttpStatus.SC_OK) {
                    Logger.d("encoding: " + connection.getHeaderField("Content-Type"));
                    Serializer serializer = new Persister();
                    Hosts hosts = serializer.read(Hosts.class, inputStream);
                    mListener.onFinishDownload(hosts);
                    CacheUtil.setToCache(mContext, new CacheObj(new Date(), hosts));
                } else if (respCode == HttpStatus.SC_NOT_MODIFIED) {
                    mListener.onFinishDownload(mCached.getObject());
                } else {
                    mListener.onError(connection.getResponseCode(), "Server response err.");
                }
            } catch (Exception e) {
                mListener.onError(-1, "Exception: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
